
package com.trydofor.id.body.shell;

import com.trydofor.id.byta.Bytable;
import com.trydofor.id.byta.ByteMeta;
import com.trydofor.id.byta.Bytes;
import com.trydofor.id.doer.shell.Outcome;

/**
 * system command
 * 
 * @author : Shi Rongjiu (www.trydofor.com)
 */
public class ShellReplyBody implements Bytable<ShellReplyBody> {
    
    private final String  command;
    private final Outcome outcome;
    
    /**
     * constructor
     * 
     * @param command the command
     * @param outcome the command outcome
     */
    public ShellReplyBody(String command, Outcome outcome) {
        this.command = command;
        this.outcome = outcome;
    }
    
    /**
     * constructor
     * 
     * @param command the command
     * @param rts the return status, 0 means successful.
     * @param out the out message
     * @param err the err message
     */
    public ShellReplyBody(String command, int rts, String out, String err) {
        this.command = command;
        this.outcome = new Outcome(rts, out, err);
    }
    
    /**
     * @return the outcome
     */
    public Outcome getOutcome() {
        return outcome;
    }
    
    /**
     * @return the command
     */
    public String getCommand() {
        return command;
    }
    
    /**
     * {@inheritDoc}
     */
    public byte[] toBytes() {
        byte[] cmd = Bytes.toMetaBytes(command);
        byte[] out = Bytes.toMetaBytes(outcome.outPut());
        byte[] err = Bytes.toMetaBytes(outcome.errPut());
        byte[] bytes = new byte[cmd.length + Bytes.BYTES_INT + out.length + err.length];
        int offset = 0;
        System.arraycopy(cmd, 0, bytes, offset, cmd.length);
        offset += cmd.length;
        Bytes.fill(bytes, offset, outcome.status());
        offset += Bytes.BYTES_INT;
        System.arraycopy(out, 0, bytes, offset, out.length);
        offset += out.length;
        System.arraycopy(err, 0, bytes, offset, err.length);
        return bytes;
    }
    
    /**
     * {@inheritDoc}
     */
    public ShellReplyBody ofBytes(byte[] bytes, int offset, int length) {
        ByteMeta<ShellReplyBody> bm = ofBytes(bytes, offset);
        return (bm.byteSize() != length) ? null : bm.instance();
    }
    
    /**
     * {@inheritDoc}
     */
    public ByteMeta<ShellReplyBody> ofBytes(byte[] bytes, int offset) {
        ShellReplyBody inst = null;
        int size = 0;
        if (!Bytes.invalidParam(bytes, offset)) {
            int count = 0;
            ByteMeta<String> cmd = Bytes.ofMetaBytes(bytes, offset + count);
            count += cmd.byteSize();
            int status = Bytes.toInt(bytes, offset + count, Bytes.BYTES_INT);
            count += Bytes.BYTES_INT;
            ByteMeta<String> out = Bytes.ofMetaBytes(bytes, offset + count);
            count += out.byteSize();
            ByteMeta<String> err = Bytes.ofMetaBytes(bytes, offset + count);
            count += err.byteSize();
            
            if (cmd.byteSize() > 0 && out.byteSize() > 0 && err.byteSize() > 0) {
                inst = new ShellReplyBody(cmd.instance(), status, out.instance(), err.instance());
                size = count;
            }
        }
        return ByteMeta.of(inst, size);
    }
}
